package test;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.junit.Test;
import org.springframework.util.StringUtils;

import java.io.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * Created by liwenlong on 2018/1/8 12:49
 */
public class JsonCompare {

    /**
     * 读取json key 生成 Java bean
     */
    int proCount = 0;
    int totalCount = 0;

    @Test
    public void readProperty() {
        //根据key生成代码
        Map<String, String> generateCode = new HashMap<>();
        //保存key的顺序
        List<String> sortedkeys = new ArrayList<>();
        int expclose = -1;
        try {
            StringBuilder builder = new StringBuilder();
            File file = new File("C:\\Users\\user\\Desktop\\json.txt");
            FileInputStream fileInputStream = new FileInputStream(file);
            InputStreamReader reader = new InputStreamReader(fileInputStream);
            BufferedReader bufferedReader = new BufferedReader(reader);

            List<String> lines = bufferedReader.lines().collect(Collectors.toList());
            for (String line : lines) {
                builder.append(line);
                if (expclose <= 0) {
                    String key = getKey(line);
                    if (StringUtils.hasText(key) && !sortedkeys.contains(key)) {
                        sortedkeys.add(key);
                    }
                }
                if (line.contains("{")) {
                    expclose++;
                }
                if (line.contains("}")) {
                    expclose--;
                }
            }
            //json字符串转换
            String s = builder.toString();
            JSONObject jsonObject = JSON.parseObject(s);
            Set<Map.Entry<String, Object>> entries = jsonObject.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                String key = entry.getKey();
                Object value = entry.getValue();
                totalCount++;
                if (value == null) {
                    generateCode.put(key, "private Object " + key + ";");
                    proCount++;
                    continue;
                }
                String className = value.getClass().getName();
                //System.out.println(className);


                if ("java.lang.Integer".equals(className) || "java.math.BigDecimal".equals(className)
                        || "java.lang.Float".equals(className) || "java.lang.Double".equals(className)) {
                    generateCode.put(key, "private Double " + key + ";");
                    proCount++;
                } else if (className.equals("java.lang.String")) {
                    generateCode.put(key, "private String " + key + ";");
                    proCount++;
                } else if (className.equals("com.alibaba.fastjson.JSONObject")) {
                    JSONObject jsonObj = (JSONObject) value;
                    Set<String> keys = jsonObj.keySet();
                    if (keys.size() > 0) {
                        String type = key.substring(0, 1).toUpperCase() + key.substring(1);
                        generateCode.put(key, "private " + type + " " + key + ";");
                        proCount++;
                    } else {
                        generateCode.put(key, "private Object " + key + ";");
                        proCount++;
                    }
                } else if (className.equals("com.alibaba.fastjson.JSONArray")) {
                    JSONArray jsonArr = (JSONArray) value;
                    if (jsonArr.size() > 0) {
                        String type = key.substring(0, 1).toUpperCase() + key.substring(1);
                        generateCode.put(key, "private List<" + type + "> " + key + ";");
                        proCount++;
                    } else {
                        generateCode.put(key, "private List<Object> " + key + ";");
                        proCount++;
                    }
                }
                //System.out.println(key+" ... "+value.getClass().getName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        int userfullCount = 0;
        for (String sortedkey : sortedkeys) {
            String s = generateCode.get(sortedkey);
            if (StringUtils.hasText(s)) {
                System.out.println(s);
                userfullCount++;
            }
        }

        System.out.println("属性个数: " + proCount);
        System.out.println("总个数: " + totalCount);
        System.out.println("有效个数: " + userfullCount);
    }

    private String getKey(String line) {
        if (StringUtils.hasText(line)) {
            String trimStr = line.trim();
            int index = trimStr.indexOf("\"");
            if (index >= 0) {
                String sub = trimStr.substring(index + 1);
                String key = sub.substring(0, sub.indexOf("\""));
                return key;
            }
        }
        return null;
    }


    /**
     * 比较两个json字符串是否相同
     * @throws InterruptedException
     */
    @Test
    public void compare() throws InterruptedException {
        long start = System.currentTimeMillis();
        String resp = "resp";
        String objToJson = "objToJson";
        String respPath = "C:\\Users\\user\\Desktop\\resp.txt";
        String objToJsonPath = "C:\\Users\\user\\Desktop\\myobj.txt";
        /*String respPath = "C:\\Users\\user\\Desktop\\myobj.txt";
        String objToJsonPath = "C:\\Users\\user\\Desktop\\resp.txt";*/
        ConcurrentMap<String, String> map = new ConcurrentHashMap<>(2);
        CountDownLatch countDownLatch = new CountDownLatch(2);
        ReadJsonTxt readJsonTxt1 = new ReadJsonTxt(respPath, map, resp, countDownLatch);
        ReadJsonTxt readJsonTxt2 = new ReadJsonTxt(objToJsonPath, map, objToJson, countDownLatch);

        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(readJsonTxt1);
        executorService.submit(readJsonTxt2);

        System.out.println("读取json文本开始:"+ LocalDateTime.now());
        countDownLatch.await();
        System.out.println("读取json文本结束:"+ LocalDateTime.now());

        String respStr = map.get(resp);
        String objToJsonStr = map.get(objToJson);
        System.out.println("耗时:"+(System.currentTimeMillis() - start));
        //json 处理
        System.out.println(respStr);
        System.out.println(objToJsonStr);

        JSONObject jsonObject1 = JSON.parseObject(respStr);
        JSONObject jsonObject2 = JSON.parseObject(objToJsonStr);
        readJsonKey(jsonObject1,jsonObject2,null);

    }

    private void readJsonKey(JSONObject obj1,JSONObject obj2,String parentKey){
        if(parentKey == null) parentKey = "";
        Set<String> keys = obj1.keySet();
        for (String key : keys) {
            String currentKey = parentKey +"->"+key;
            Object value1 = obj1.get(key);
            Object value2 = obj2.get(key);
            if(value1 == null){
                //System.out.println("resp json key: "+currentKey+" ,value1:"+value1+" value2:"+value2);
                continue;
            }
            if(value2 == null){
                System.out.println("java obj key "+currentKey+" ,"+value1+" "+value2);
                continue;
            }
            if(value1 instanceof JSONObject){
                readJsonKey(obj1.getJSONObject(key),obj2.getJSONObject(key),currentKey);
                continue;
            }else if(value1 instanceof JSONArray){
                JSONArray jsonArray1 = obj1.getJSONArray(key);
                JSONArray jsonArray2 = obj2.getJSONArray(key);
                if(jsonArray1 != null){
                    int size = jsonArray1.size();
                    for (int i = 0; i < size; i++) {
                        JSONObject jsonObject1 = jsonArray1.getJSONObject(i);
                        JSONObject jsonObject2 = jsonArray2.getJSONObject(i);
                        readJsonKey(jsonObject1,jsonObject2,currentKey+"_"+i);
                    }
                }
                continue;
            }
            if(!value1.equals(value2)){
                System.out.println("key:"+currentKey+" =>"+value1+" "+value2);
            }
        }
    }


    /**
     * 读取json
     */
    static class ReadJsonTxt implements Runnable {
        private String txtPath;
        private ConcurrentMap<String, String> map;
        private String mapKey;
        private CountDownLatch countDownLatch;

        ReadJsonTxt(String txtPath, ConcurrentMap<String, String> map, String mapKey, CountDownLatch countDownLatch) {
            this.txtPath = txtPath;
            this.map = map;
            this.mapKey = mapKey;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                StringBuilder builder = new StringBuilder();
                File file = new File(txtPath);
                FileInputStream fileInputStream = new FileInputStream(file);
                InputStreamReader reader = new InputStreamReader(fileInputStream);
                BufferedReader bufferedReader = new BufferedReader(reader);
                bufferedReader.lines().forEach(builder::append);
                String s = builder.toString();
                map.put(mapKey, s);
                countDownLatch.countDown();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}
